//==============================================================================
// Copyright (c) 2008-2013 Niall Ryan. All Rights Reserved.
//==============================================================================

#ifndef HYDRA_THREADLOCAL_H
#define HYDRA_THREADLOCAL_H 1

#include "internal/threadlocal_internal.h"

namespace Hydra
{
	/**
	 * Similar semantics to a smart pointer of type T, this way it will work for both simple types and structs. If sizeof(T) is more than
	 * 4 bytes, then it will be constructed on the heap for each thread, otherwise will be efficiently stored directly in TLS memory.
	 * TODO: destruction? how to destruct all the copies for each thread? keep a list perhaps? shouldn't we really call the constructor and
	 *       destructor for types less than 4 bytes too? could use VC intrinsics to check if type has a constructor/destructor... other compilers
	 *       could just check if the type is fundamental, which would fail only in the case of a <4 byte POD structure, where an unnecessary list would be kept.
	 *   Cases: Fundamental type or <4 byte POD structure         - no heap storage, no initial construct, no destruct list
	 *          <4 byte structure with constructor                - no heap storage, initial construct, no destruct list
	 *          <4 byte structure with destructor                 - no heap storage, no initial construct, destruct list
	 *          <4 byte structure with constructor and destructor - no heap storage, initial construct, destruct list
	 *          >4 byte structure                                 - heap storage, initial construct and destruct list required whether or not type has a destructor
	 * TODO: 8 byte fundamental types? use a pool of 8 bytes for everything or keep multiple pools?
	 */
	template<typename T>
	class ThreadLocal
	{
	public:
		ThreadLocal()
		{
			m_index = m_alloc.allocIndex();
		}
		~ThreadLocal()
		{
			m_alloc.freeIndex(m_index);
		}
		T* get()
		{
			return m_alloc.get(m_index);
		}
		T* operator->()		{ return get(); }
		T& operator*()		{ return *get(); }

	private:
		unsigned int m_index;
		typename Internal::ThreadLocalPolicies<T, sizeof(T)>::Alloc m_alloc;	//TODO: zero size object optimization needed here? (merge with m_index fix)
	};
}

#endif
